package com.shelly.juc;

import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

/**
 * @author: Shelly
 * @create: 2024-01-26 17:01:36
 * @version: 1.0
 * @describe: 实现多线程方法:3、Callable的方式
 * 之前的两种创建线程的方式都是重写run方法
 * 缺点：
 * 1、run方法是没有返回结果的：不知道开启的线程什么时候开始执行，什么时候结束执行，也获取不到对应的返回结果
 * 2、run方法也不能把可能产生的异常抛出
 *
 * 解决：在JDK1.5之后推出了通过实现Callable接口的方式来创建新的线程，这种方式可以获取对应的返回结果
 *
 * 实现Runnable接口和实现Callable接口的区别:
 * 1. Runnable是自从java1.1就有了，而Callable是1.5之后才加上去的
 * 2. Callable规定的方法是call(),Runnable规定的方法是run()
 * 3. Callable的任务执行后可返回值，而Runnable的任务是不能返回值(是void)
 * 4. call方法可以抛出异常，run方法不可以
 * 5. 运行Callable任务可以拿到一个Future对象，表示异步计算的结果。它提供了检查计算是否完成的方法，以等待计算的完成，并检索计算的结果。通过Future对象可以了解任务执行情况，可取消任务的执行，还可获取执行结果。
 * 6. 加入线程池运行，Runnable使用ExecutorService的execute方法，Callable使用submit方法。
 *
 * 本质：Callable接口底层的实现就是对Runable接口实现的封装
 * 线程启动执行的也是Runable接口实现中的run方法，只是在run方法中有调用call方法罢了
 */
public class Create03 {
    /**
     * 创建线程的第三种实现方式：
     *    Callable方式
     */
    public static void main(String[] args) throws  Exception {
        // 创建一个Callable实例
        Callable<Integer> callable = new MyCallable();
        FutureTask<Integer> futureTask = new FutureTask<>(callable);
        // 获取一个线程 肯定是要先创建一个Thread对象  futureTask本质上是Runable接口的实现
        Thread t1 = new Thread(futureTask);
        System.out.println("main方法start....");
        t1.start(); // 本质还是执行的 Runable中的run方法，只是 run方法调用了call方法罢了
        // 获取返回的结果
        System.out.println(futureTask.get()); // 获取开启的线程执行完成后返回的结果
        System.out.println("main方法end ....");

    }
}
/**
 * 创建Callable的实现类
 *    我们需要指定Callable的泛型，这个泛型是返回结果的类型
 */
class MyCallable implements Callable<Integer> {

    /**
     * 线程自动后会执行的方法
     * @return
     * @throws Exception
     */
    @Override
    public Integer call() throws Exception {
        int sum = 0;
        for(int i = 1 ; i <= 100 ; i ++){
            sum += i;
        }
        return sum;
    }
}